package pl.un4giv3n.mightvsmagic.utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import pl.un4giv3n.mightvsmagic.entity.BonusType;
import pl.un4giv3n.mightvsmagic.entity.Clan;
import pl.un4giv3n.mightvsmagic.entity.ClanBattle;
import pl.un4giv3n.mightvsmagic.entity.ClanWar;
import pl.un4giv3n.mightvsmagic.entity.FightReport;
import pl.un4giv3n.mightvsmagic.entity.User;
import pl.un4giv3n.mightvsmagic.entity.UserType;

public final class ClanUtil {
	
	public static final long MIN_BATTLE_DIFF = 1000 * 7200; //2h
	
	private ClanUtil(){}

	public static String getClanBonusInfo(Clan clan) {
		int altarLevel = clan.getAltarLevel();
		BonusType bonus = clan.getGuardian().getBonus();
		StringBuilder builder = new StringBuilder();
		switch(bonus){
		case ATTACK: builder.append("sztuka walki +").append(getSkillBonus(altarLevel)); break;
		case PARRY: builder.append("unik +").append(getSkillBonus(altarLevel)); break;
		case STAMINA: builder.append("wytrzymałość +").append(getSkillBonus(altarLevel)); break;
		case STRENGTH: builder.append("siła +").append(getSkillBonus(altarLevel)); break;
		case MANA: builder.append("mana +").append(getSkillBonus(altarLevel)); break;
		case LIFE: builder.append("żywotność +").append(getSkillBonus(altarLevel)); break;
		case SPEED: builder.append("szybkość +").append(getSkillBonus(altarLevel)); break;
		case WATER: builder.append("obrażenia od wody +").append(getElementalBonus(altarLevel)).append(", obrona od wody +").append(getElementalBonus(altarLevel));break;
		case FIRE: builder.append("obrażenia od ognia +").append(getElementalBonus(altarLevel)).append(", obrona od ognia +").append(getElementalBonus(altarLevel));break;
		case EARTH: builder.append("obrażenia od ziemi +").append(getElementalBonus(altarLevel)).append(", obrona od ziemi +").append(getElementalBonus(altarLevel));break;
		case WIND: builder.append("obrażenia od powietrza +").append(getElementalBonus(altarLevel)).append(", obrona od powietrza +").append(getElementalBonus(altarLevel));break;
		case GOLD: builder.append("dodatkowe złoto z pracy +").append(getGoldBonus(altarLevel));break;
		case MAGIC_EXP: builder.append("dodatkowe doświadczenie magiczne z treningu +").append(getExpBonus(altarLevel));break;
		case FIGHT_EXP: builder.append("dodatkowe doświadczenie bojowe z treningu +").append(getExpBonus(altarLevel));break;
		}
		
		return builder.toString();
	}

	private static long getExpBonus(int altarLevel) {
		return altarLevel;
	}

	private static long getGoldBonus(int altarLevel) {
		return altarLevel * 10;
	}

	private static long getElementalBonus(int altarLevel) {
		return altarLevel * 2;
	}

	private static long getSkillBonus(int altarLevel) {
		return altarLevel * 4;
	}
	
	public static long getAttackBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.ATTACK){
			return getSkillBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getParryBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.PARRY){
			return getSkillBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getManaBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.MANA){
			return getSkillBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getStaminaBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.STAMINA){
			return getSkillBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getStrengthBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.STRENGTH){
			return getSkillBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getSpeedBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.SPEED){
			return getSkillBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getLifeBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.LIFE){
			return getSkillBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getWaterBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.WATER){
			return getElementalBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getWindBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.WIND){
			return getElementalBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getFireBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.FIRE){
			return getElementalBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getEarthBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.EARTH){
			return getElementalBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getFightExpBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.FIGHT_EXP){
			return getExpBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getMagicExpBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.MAGIC_EXP){
			return getExpBonus(clan.getAltarLevel());
		}
		return 0;
	}
	public static long getGoldBonus(Clan clan){
		if(clan.getGuardian().getBonus() == BonusType.GOLD){
			return getGoldBonus(clan.getAltarLevel());
		}
		return 0;
	}

	public static long getAltarImprovementCost(Clan clan) {
		int altarLevel = clan.getAltarLevel();
		return Math.round(10000*Math.pow(altarLevel,3)+10000/altarLevel);
	}
	public static long getTowerImprovementCost(Clan clan) {
		int altarLevel = clan.getTowerLevel();
		return Math.round(10000*altarLevel*altarLevel+10000/altarLevel);
	}
	public static long getBarracksImprovementCost(Clan clan) {
		int altarLevel = clan.getBarracksLevel();
		return Math.round(10000*altarLevel*altarLevel+10000/altarLevel);
	}

	public static long getMaxKnightCount(Clan clan) {
		return clan.getBarracksLevel()*2;
	}

	public static long getMaxMageCount(Clan clan) {
		return clan.getTowerLevel()*2;
	}

	public static boolean canJoinClan(Clan clan, User pendingUser) {
		boolean canJoin = false;
		if(pendingUser.getUserType() == UserType.KNIGHT && getKnightsCount(clan) < getMaxKnightCount(clan)){
			canJoin = true;
		}
		if(pendingUser.getUserType() == UserType.MAGE && getMagesCount(clan) < getMaxMageCount(clan)){
			canJoin = true;
		}
		return canJoin;
	}

	private static long getKnightsCount(Clan clan) {
		int knights = 0;
		for (User user : clan.getUsers()) {
			if(user.getUserType() == UserType.KNIGHT){
				knights++;
			}
		}
		return knights;
	}
	private static long getMagesCount(Clan clan) {
		int mages = 0;
		for (User user : clan.getUsers()) {
			if(user.getUserType() == UserType.MAGE){
				mages++;
			}
		}
		return mages;
	}
	
	@SuppressWarnings("unchecked")
	public static List<ClanWar> getCurrentClanWars(Clan clan, EntityManager em){
		Query query = em.createNamedQuery("find.current.clan.wars");
		query.setParameter("clanId", clan.getId());
		return query.getResultList();
	}
	@SuppressWarnings("unchecked")
	public static List<ClanWar> getOldClanWars(Clan clan, EntityManager em){
		Query query = em.createNamedQuery("find.old.clan.wars");
		query.setParameter("clanId", clan.getId());
		return query.getResultList();
	}

	public static ClanBattle doBattle(ClanWar war, EntityManager em) {
		ClanBattle battle = new ClanBattle();
		battle.setDate(new Date());
		Clan attackingClan = em.find(Clan.class, war.getAttackerId());
		Clan defendingClan = em.find(Clan.class, war.getDefenderId());
		List<User> attackers = new ArrayList<User>(attackingClan.getUsers());
		List<User> defenders = new ArrayList<User>(defendingClan.getUsers());
		while(!attackers.isEmpty() && !defenders.isEmpty()){
			doClash(battle, attackers, defenders);
		}
		if(attackers.isEmpty()){
			battle.setWinnerId(defendingClan.getId());
			battle.setWinnerName(defendingClan.getName());
		}else{
			battle.setWinnerId(attackingClan.getId());
			battle.setWinnerName(attackingClan.getName());
		}
		return battle;
	}

	private static void doClash(ClanBattle battle, List<User> attackers,
			List<User> defenders) {
		Collections.shuffle(attackers);
		Collections.shuffle(defenders);
		int min = Math.min(attackers.size(), defenders.size());
		for (int i = 0; i < min; i++) {
			User attacker = attackers.get(i);
			User defender = defenders.get(i);
			FightReport fight = FightUtil.fight(attacker, defender);
			fight.setClanWarReport(true);
			battle.getFights().add(fight);
		}
		for (Iterator<User> iterator = defenders.iterator(); iterator.hasNext();) {
			User user = iterator.next();
			if(user.getHp()<=0){
				iterator.remove();
			}
		}
		for (Iterator<User> iterator = attackers.iterator(); iterator.hasNext();) {
			User user = iterator.next();
			if(user.getHp()<=0){
				iterator.remove();
			}
		}
	}
	public static int getAttackerWins(ClanWar war){
		int wins = 0;
		List<ClanBattle> battles = war.getBattles();
		for (ClanBattle clanBattle : battles) {
			long winnerId = clanBattle.getWinnerId().longValue();
			if(winnerId == war.getAttackerId().longValue()){
				wins++;
			}
		}
		return wins;

	}
	public static int getDefenderWins(ClanWar war){
		int wins = 0;
		List<ClanBattle> battles = war.getBattles();
		for (ClanBattle clanBattle : battles) {
			long winnerId = clanBattle.getWinnerId().longValue();
			if(winnerId == war.getDefenderId().longValue()){
				wins++;
			}
		}
		return wins;
		
	}
	
	@SuppressWarnings("unchecked")
	public static void endClanWars(Long clanId, EntityManager entityManager) {
		Query query = entityManager.createNamedQuery("find.current.clan.wars");
		query.setParameter("clanId", clanId);
		List<ClanWar> wars = query.getResultList();
		for (ClanWar clanWar : wars) {
			clanWar.setFinished(true);
			long winnerId = 0;
			if(clanWar.getAttackerId().longValue() == clanId){
				winnerId = clanWar.getDefenderId();
			}else{
				winnerId = clanWar.getAttackerId();
			}
			Clan winner = entityManager.find(Clan.class, winnerId);
			Clan looser = entityManager.find(Clan.class, clanId);
			clanWar.setWinnerId(winner.getId());
			clanWar.setWinnerName(winner.getName());
			long goldMove = looser.getGold()/10;
			clanWar.setGold(goldMove);
			winner.addGold(goldMove);
			looser.removeGold(goldMove);
			entityManager.merge(clanWar);
			entityManager.merge(winner);
			entityManager.merge(looser);
		}
		
	}

}
